package com.example.springbootlucenedemo.http;

import com.example.springbootlucenedemo.bean.TbMission;
import com.example.springbootlucenedemo.common.lucene.IndexService;
import com.example.springbootlucenedemo.common.lucene.bean.EntityUtil;
import com.example.springbootlucenedemo.common.lucene.conf.LuceneConf;
import com.example.springbootlucenedemo.service.impl.TbMissionServiceImpl;
import com.example.springbootlucenedemo.service.impl.TbUsersInfoServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Function;

@Slf4j
@RestController
@RequestMapping("")
public class MissionController {
    @Autowired
    TbMissionServiceImpl tbMissionService;
    @Autowired
    TbUsersInfoServiceImpl tbUsersInfoService;
    @Autowired
    IndexService index;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    LuceneConf luceneConf;
    ExecutorService executorService =    new ThreadPoolExecutor(8, 12,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(16),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 增量初始化
     * @param force 强制
     */
    @GetMapping("init/mission")
    public void init(@RequestParam(value = "force",defaultValue = "false") Boolean force){
        // 强制重建 Document
        if(force){
            redisTemplate.delete(EntityUtil.getLuceneIndexPath(new TbMission()));
            index.deleteDocument(new TbMission());
        }
        // 是否已经成功建立Document
        Function<Long, Boolean> isExist = (mission_id) -> {
            if(force){
                return  false;
            }
            return redisTemplate.opsForValue().getBit(EntityUtil.getLuceneIndexPath(new TbMission()), EntityUtil.hashByPrimarykeys(String.valueOf(mission_id)));
        };
        // 创建Document
        Consumer<Long> addDocument = (mission_id) -> {
            TbMission tbMission = tbMissionService.tbMissionDao.findTbMissionByMission_id(mission_id);
            if(tbMission!=null){
                index.addDocument(tbMission);
                redisTemplate.opsForValue().setBit(EntityUtil.getLuceneIndexPath(new TbMission()), EntityUtil.hashByPrimarykey(tbMission), false);
            }
        };
        // 分页处理数据
        final int pageSize = 1000;
        final long countTbMission = tbMissionService.tbMissionDao.countListTbMissionByother();
        long c= (countTbMission / pageSize) + 1L;
        for (int i = 0; i < c; i++) {
            final int finalI = i;
            executorService.submit(new Thread(()->{
                List<Long> missions = tbMissionService.tbMissionDao.listTbMissionIdByother(pageSize,finalI*pageSize);
                for(Long mission:missions){
                    if(!isExist.apply(mission)){
                        addDocument.accept(mission);
                    }
                }
                System.out.println("第"+ finalI +" / "+c+" 页");
            }));
        }
    }

    @GetMapping("mission")
    public List<Map<String,Object>> search(Long mission_id,String rpermCode, Integer[] stateId,Integer missionType, String keyWord,String order){
        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        try {
            if( !org.springframework.util.StringUtils.isEmpty(mission_id)){
                builder.add(LongPoint.newSetQuery("mission_id", mission_id), BooleanClause.Occur.MUST);
            }
            if( !org.springframework.util.StringUtils.isEmpty(rpermCode)){
                builder.add(new PrefixQuery(new Term("rperm_code",rpermCode)), BooleanClause.Occur.MUST);
            }
            if( stateId!=null && stateId.length>0){
                BooleanQuery.Builder builders = new BooleanQuery.Builder();
                for (int i = 0; i < stateId.length; i++) {
                    builders.add(LongPoint.newSetQuery("state", Integer.valueOf(stateId[i])), BooleanClause.Occur.SHOULD);
                }
                builder.add(builders.build(), BooleanClause.Occur.MUST);
            }
            if( !org.springframework.util.StringUtils.isEmpty(missionType)){
                builder.add(new QueryParser("mission_type", luceneConf.getAnalyzer()).parse(String.valueOf(missionType)), BooleanClause.Occur.MUST);
            }
            if( !org.springframework.util.StringUtils.isEmpty(keyWord)){
                BooleanQuery.Builder builders = new BooleanQuery.Builder();

                /*builders.add(new FuzzyQuery(new Term("subject",keyWord)), BooleanClause.Occur.SHOULD);
                builders.add(new FuzzyQuery(new Term("detail_info",keyWord)), BooleanClause.Occur.SHOULD);
                builders.add(new FuzzyQuery(new Term("mission_id",keyWord)), BooleanClause.Occur.SHOULD);*/

            /* builders.add(new WildcardQuery(new Term("subject","*"+keyWord+"*")), BooleanClause.Occur.SHOULD);
                    builders.add(new WildcardQuery(new Term("detail_info","*"+keyWord+"*")), BooleanClause.Occur.SHOULD);
                    builders.add(new WildcardQuery(new Term("mission_id","*"+keyWord+"*")), BooleanClause.Occur.SHOULD);*/
                    builders.add(new QueryParser("subject", luceneConf.getAnalyzer()).parse(keyWord), BooleanClause.Occur.SHOULD);
                    builders.add(new QueryParser("detail_info", luceneConf.getAnalyzer()).parse(keyWord), BooleanClause.Occur.SHOULD);
                    builders.add(new QueryParser("mission_id", luceneConf.getAnalyzer()).parse(keyWord), BooleanClause.Occur.SHOULD);
                builder.add(builders.build(), BooleanClause.Occur.MUST);
            }

            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, 720);
            long currentTime = c.getTime().getTime() / 1000;
            builder.add(LongPoint.newRangeQuery("start_date", -1, currentTime), BooleanClause.Occur.MUST);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Sort sort = new Sort(SortField.FIELD_SCORE);
        if( org.springframework.util.StringUtils.isEmpty(order)){
            sort= new Sort(
                    // SortField.FIELD_SCORE,
                    new SortField("create_datetime", SortField.Type.LONG, true));
        }else if(order.equals("1")){
            sort= new Sort(
                    // SortField.FIELD_SCORE,
                    new SortField("start_date", SortField.Type.LONG, true),
                    new SortField("state", SortField.Type.LONG, false));
        }else if(order.equals("2")){
            sort= new Sort(
                    // SortField.FIELD_SCORE,
                    new SortField("browse_count", SortField.Type.LONG, true),
                    new SortField("state", SortField.Type.LONG, false));
        }
        Query query = builder.build();
        List<Map<String,Object>> list =   index.search(1,50,   sort, query);
        return list;
    }
    @GetMapping("delete")
    public void delete(Long mission_id){
        TbMission tbMission = new TbMission();
            tbMission.setMission_id(mission_id);
        index.deleteDocument(tbMission);
    }
    @GetMapping("update")
    public void update(Long mission_id){
        TbMission m = tbMissionService.tbMissionDao.findTbMissionByMission_id(mission_id);
        m.setSubject(m.getSubject()+" update");
        index.updateDocument(m);
    }
    @GetMapping("/add/{id}")
    public void add(@PathVariable("id") Long id){
        TbMission tbMission = tbMissionService.tbMissionDao.getById(id);
        Long aLong = index.addDocument(tbMission);
        System.out.println(aLong);
    }
}
